Есть в C# такой хитрый атрибут как StructLayoutAttribute, с помощью него можно задавать расположение членов класса(структуры) как мы хотим. Имеет два конструктора:
StructLayoutAttribute(short) StructLayoutAttribute(LayoutKind)
Рассмотрим второй конструктор LayoutKind - задаёт расположение членов класса.
public enum LayoutKind
Члены этого перечисления:
Рассмотрим два последние значения. У нас есть следующая структура:
public struct Test
{
int i;
byte j;
}
Как вы думаете какой размер будет у неё 5 байт? Вовсе нет, по умолчанию выравнивание у нас идёт по 8. Просто сделаем:
Test s = new Test();
unsafe
{
Console.WriteLine("size is {0}", sizeof(Test));
}
Здесь мы получим результат 8, но мы можем сделать следующее:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Test
{
int i;
byte j;
}
Член Pack отвечает за выравнивание, по умолчанию он равен 8, поэтому мы изменим его значение на 1 и получим структуру которая будет выровнена на границе 1 байта. После чего её размер будет равен уже 5 байтам. С помощью Explicit как я уже говорил можно точно указать расположение членов класса. Пример.
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct Test2
{
[FieldOffset(0)] public int i;
[FieldOffset(3)] public byte j;
}
Теперь уже размер структуры будет равен 4. Но если мы присвоим значение 3 j, то i не будет равно 3. Мы получим число 50331648. Всё это потому что у нас байты хранятся наоборот если помните( типа L(младший байт)H(старший байт). В шестнадцатеричной системе 50331648 будет равно 0x3000000. Не забывайте об этом.